home *** CD-ROM | disk | FTP | other *** search
/ CD/PC Actual 31 / PC Actual CD 31.iso / dists / SRC / SLIBEXEC.AA / SLIBEXEC / libexec / rbootd / rbootd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-24  |  10.3 KB  |  460 lines

  1. /*
  2.  * Copyright (c) 1988, 1992 The University of Utah and the Center
  3.  *    for Software Science (CSS).
  4.  * Copyright (c) 1992, 1993
  5.  *    The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * This code is derived from software contributed to Berkeley by
  8.  * the Center for Software Science of the University of Utah Computer
  9.  * Science Department.  CSS requests users of this software to return
  10.  * to css-dist@cs.utah.edu any improvements that they make and grant
  11.  * CSS redistribution rights.
  12.  *
  13.  * Redistribution and use in source and binary forms, with or without
  14.  * modification, are permitted provided that the following conditions
  15.  * are met:
  16.  * 1. Redistributions of source code must retain the above copyright
  17.  *    notice, this list of conditions and the following disclaimer.
  18.  * 2. Redistributions in binary form must reproduce the above copyright
  19.  *    notice, this list of conditions and the following disclaimer in the
  20.  *    documentation and/or other materials provided with the distribution.
  21.  * 3. All advertising materials mentioning features or use of this software
  22.  *    must display the following acknowledgement:
  23.  *    This product includes software developed by the University of
  24.  *    California, Berkeley and its contributors.
  25.  * 4. Neither the name of the University nor the names of its contributors
  26.  *    may be used to endorse or promote products derived from this software
  27.  *    without specific prior written permission.
  28.  *
  29.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  30.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  31.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  32.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  33.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  34.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  35.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  36.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  37.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  38.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  39.  * SUCH DAMAGE.
  40.  *
  41.  *    from: @(#)rbootd.c    8.1 (Berkeley) 6/4/93
  42.  *
  43.  * From: Utah Hdr: rbootd.c 3.1 92/07/06
  44.  * Author: Jeff Forys, University of Utah CSS
  45.  */
  46.  
  47. #ifndef lint
  48. static const char copyright[] =
  49. "@(#) Copyright (c) 1992, 1993\n\
  50.     The Regents of the University of California.  All rights reserved.\n";
  51. #endif /* not lint */
  52.  
  53. #ifndef lint
  54. #if 0
  55. static const char sccsid[] = "@(#)rbootd.c    8.1 (Berkeley) 6/4/93";
  56. #endif
  57. static const char rcsid[] =
  58.     "$Id: rbootd.c,v 1.9 1997/11/24 07:33:41 charnier Exp $";
  59. #endif /* not lint */
  60.  
  61. #include <sys/param.h>
  62. #include <sys/time.h>
  63. #include <ctype.h>
  64. #include <err.h>
  65. #include <errno.h>
  66. #include <fcntl.h>
  67. #include <signal.h>
  68. #include <stdio.h>
  69. #include <stdlib.h>
  70. #include <string.h>
  71. #include <syslog.h>
  72. #include <unistd.h>
  73. #include "defs.h"
  74.  
  75. static void usage __P((void));
  76.  
  77. int
  78. main(argc, argv)
  79.     int argc;
  80.     char *argv[];
  81. {
  82.     int c, fd, omask, maxfds;
  83.     fd_set rset;
  84.  
  85.     /*
  86.      *  Close any open file descriptors.
  87.      *  Temporarily leave stdin & stdout open for `-d',
  88.      *  and stderr open for any pre-syslog error messages.
  89.      */
  90.     {
  91.         int i, nfds = getdtablesize();
  92.  
  93.         for (i = 0; i < nfds; i++)
  94.             if (i != fileno(stdin) && i != fileno(stdout) &&
  95.                 i != fileno(stderr))
  96.                 (void) close(i);
  97.     }
  98.  
  99.     /*
  100.      *  Parse any arguments.
  101.      */
  102.     while ((c = getopt(argc, argv, "adi:")) != -1)
  103.         switch(c) {
  104.             case 'a':
  105.             BootAny++;
  106.             break;
  107.             case 'd':
  108.             DebugFlg++;
  109.             break;
  110.             case 'i':
  111.             IntfName = optarg;
  112.             break;
  113.             default:
  114.             usage();
  115.         }
  116.     for (; optind < argc; optind++) {
  117.         if (ConfigFile == NULL)
  118.             ConfigFile = argv[optind];
  119.         else {
  120.             warnx("too many config files (`%s' ignored)",
  121.                 argv[optind]);
  122.         }
  123.     }
  124.  
  125.     if (ConfigFile == NULL)            /* use default config file */
  126.         ConfigFile = DfltConfig;
  127.  
  128.     if (DebugFlg) {
  129.         DbgFp = stdout;                /* output to stdout */
  130.  
  131.         (void) signal(SIGUSR1, SIG_IGN);    /* dont muck w/DbgFp */
  132.         (void) signal(SIGUSR2, SIG_IGN);
  133.         (void) fclose(stderr);            /* finished with it */
  134.     } else {
  135.         if (daemon(0, 0))
  136.             err(1, "can't detach from terminal");
  137.  
  138.         (void) signal(SIGUSR1, DebugOn);
  139.         (void) signal(SIGUSR2, DebugOff);
  140.     }
  141.  
  142.     openlog("rbootd", LOG_PID, LOG_DAEMON);
  143.  
  144.     /*
  145.      *  If no interface was specified, get one now.
  146.      *
  147.      *  This is convoluted because we want to get the default interface
  148.      *  name for the syslog("restarted") message.  If BpfGetIntfName()
  149.      *  runs into an error, it will return a syslog-able error message
  150.      *  (in `errmsg') which will be displayed here.
  151.      */
  152.     if (IntfName == NULL) {
  153.         char *errmsg;
  154.  
  155.         if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) {
  156.             syslog(LOG_NOTICE, "restarted (??)");
  157.             syslog(LOG_ERR, errmsg);
  158.             Exit(0);
  159.         }
  160.     }
  161.  
  162.     syslog(LOG_NOTICE, "restarted (%s)", IntfName);
  163.  
  164.     (void) signal(SIGHUP, ReConfig);
  165.     (void) signal(SIGINT, Exit);
  166.     (void) signal(SIGTERM, Exit);
  167.  
  168.     /*
  169.      *  Grab our host name and pid.
  170.      */
  171.     if (gethostname(MyHost, MAXHOSTNAMELEN) < 0) {
  172.         syslog(LOG_ERR, "gethostname: %m");
  173.         Exit(0);
  174.     }
  175.     MyHost[MAXHOSTNAMELEN] = '\0';
  176.  
  177.     MyPid = getpid();
  178.  
  179.     /*
  180.      *  Write proc's pid to a file.
  181.      */
  182.     {
  183.         FILE *fp;
  184.  
  185.         if ((fp = fopen(PidFile, "w")) != NULL) {
  186.             (void) fprintf(fp, "%d\n", (int) MyPid);
  187.             (void) fclose(fp);
  188.         } else {
  189.             syslog(LOG_WARNING, "fopen: failed (%s)", PidFile);
  190.         }
  191.     }
  192.  
  193.     /*
  194.      *  All boot files are relative to the boot directory, we might
  195.      *  as well chdir() there to make life easier.
  196.      */
  197.     if (chdir(BootDir) < 0) {
  198.         syslog(LOG_ERR, "chdir: %m (%s)", BootDir);
  199.         Exit(0);
  200.     }
  201.  
  202.     /*
  203.      *  Initial configuration.
  204.      */
  205.     omask = sigblock(sigmask(SIGHUP));    /* prevent reconfig's */
  206.     if (GetBootFiles() == 0)        /* get list of boot files */
  207.         Exit(0);
  208.     if (ParseConfig() == 0)            /* parse config file */
  209.         Exit(0);
  210.  
  211.     /*
  212.      *  Open and initialize a BPF device for the appropriate interface.
  213.      *  If an error is encountered, a message is displayed and Exit()
  214.      *  is called.
  215.      */
  216.     fd = BpfOpen();
  217.  
  218.     (void) sigsetmask(omask);        /* allow reconfig's */
  219.  
  220.     /*
  221.      *  Main loop: receive a packet, determine where it came from,
  222.      *  and if we service this host, call routine to handle request.
  223.      */
  224.     maxfds = fd + 1;
  225.     FD_ZERO(&rset);
  226.     FD_SET(fd, &rset);
  227.     for (;;) {
  228.         struct timeval timeout;
  229.         fd_set r;
  230.         int nsel;
  231.  
  232.         r = rset;
  233.  
  234.         if (RmpConns == NULL) {        /* timeout isnt necessary */
  235.             nsel = select(maxfds, &r, NULL, NULL, NULL);
  236.         } else {
  237.             timeout.tv_sec = RMP_TIMEOUT;
  238.             timeout.tv_usec = 0;
  239.             nsel = select(maxfds, &r, NULL, NULL, &timeout);
  240.         }
  241.  
  242.         if (nsel < 0) {
  243.             if (errno == EINTR)
  244.                 continue;
  245.             syslog(LOG_ERR, "select: %m");
  246.             Exit(0);
  247.         } else if (nsel == 0) {        /* timeout */
  248.             DoTimeout();            /* clear stale conns */
  249.             continue;
  250.         }
  251.  
  252.         if (FD_ISSET(fd, &r)) {
  253.             RMPCONN rconn;
  254.             CLIENT *client, *FindClient();
  255.             int doread = 1;
  256.  
  257.             while (BpfRead(&rconn, doread)) {
  258.                 doread = 0;
  259.  
  260.                 if (DbgFp != NULL)    /* display packet */
  261.                     DispPkt(&rconn,DIR_RCVD);
  262.  
  263.                 omask = sigblock(sigmask(SIGHUP));
  264.  
  265.                 /*
  266.                  *  If we do not restrict service, set the
  267.                  *  client to NULL (ProcessPacket() handles
  268.                  *  this).  Otherwise, check that we can
  269.                  *  service this host; if not, log a message
  270.                  *  and ignore the packet.
  271.                  */
  272.                 if (BootAny) {
  273.                     client = NULL;
  274.                 } else if ((client=FindClient(&rconn))==NULL) {
  275.                     syslog(LOG_INFO,
  276.                            "%s: boot packet ignored",
  277.                            EnetStr(&rconn));
  278.                     (void) sigsetmask(omask);
  279.                     continue;
  280.                 }
  281.  
  282.                 ProcessPacket(&rconn,client);
  283.  
  284.                 (void) sigsetmask(omask);
  285.             }
  286.         }
  287.     }
  288. }
  289.  
  290. static void
  291. usage()
  292. {
  293.     fprintf(stderr, "usage: rbootd [-ad] [-i interface] [config_file]\n");
  294.     exit (1);
  295. }
  296.  
  297. /*
  298. **  DoTimeout -- Free any connections that have timed out.
  299. **
  300. **    Parameters:
  301. **        None.
  302. **
  303. **    Returns:
  304. **        Nothing.
  305. **
  306. **    Side Effects:
  307. **        - Timed out connections in `RmpConns' will be freed.
  308. */
  309. void
  310. DoTimeout()
  311. {
  312.     RMPCONN *rtmp;
  313.     struct timeval now;
  314.  
  315.     (void) gettimeofday(&now, (struct timezone *)0);
  316.  
  317.     /*
  318.      *  For each active connection, if RMP_TIMEOUT seconds have passed
  319.      *  since the last packet was sent, delete the connection.
  320.      */
  321.     for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
  322.         if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) {
  323.             syslog(LOG_WARNING, "%s: connection timed out (%u)",
  324.                    EnetStr(rtmp), rtmp->rmp.r_type);
  325.             RemoveConn(rtmp);
  326.         }
  327. }
  328.  
  329. /*
  330. **  FindClient -- Find client associated with a packet.
  331. **
  332. **    Parameters:
  333. **        rconn - the new packet.
  334. **
  335. **    Returns:
  336. **        Pointer to client info if found, NULL otherwise.
  337. **
  338. **    Side Effects:
  339. **        None.
  340. **
  341. **    Warnings:
  342. **        - This routine must be called with SIGHUP blocked since
  343. **          a reconfigure can invalidate the information returned.
  344. */
  345.  
  346. CLIENT *
  347. FindClient(rconn)
  348.     RMPCONN *rconn;
  349. {
  350.     CLIENT *ctmp;
  351.  
  352.     for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next)
  353.         if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
  354.                  (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0)
  355.             break;
  356.  
  357.     return(ctmp);
  358. }
  359.  
  360. /*
  361. **  Exit -- Log an error message and exit.
  362. **
  363. **    Parameters:
  364. **        sig - caught signal (or zero if not dying on a signal).
  365. **
  366. **    Returns:
  367. **        Does not return.
  368. **
  369. **    Side Effects:
  370. **        - This process ceases to exist.
  371. */
  372. void
  373. Exit(sig)
  374.     int sig;
  375. {
  376.     if (sig > 0)
  377.         syslog(LOG_ERR, "going down on signal %d", sig);
  378.     else
  379.         syslog(LOG_ERR, "going down with fatal error");
  380.     BpfClose();
  381.     exit(1);
  382. }
  383.  
  384. /*
  385. **  ReConfig -- Get new list of boot files and reread config files.
  386. **
  387. **    Parameters:
  388. **        None.
  389. **
  390. **    Returns:
  391. **        Nothing.
  392. **
  393. **    Side Effects:
  394. **        - All active connections are dropped.
  395. **        - List of boot-able files is changed.
  396. **        - List of clients is changed.
  397. **
  398. **    Warnings:
  399. **        - This routine must be called with SIGHUP blocked.
  400. */
  401. void
  402. ReConfig(signo)
  403.     int signo;
  404. {
  405.     syslog(LOG_NOTICE, "reconfiguring boot server");
  406.  
  407.     FreeConns();
  408.  
  409.     if (GetBootFiles() == 0)
  410.         Exit(0);
  411.  
  412.     if (ParseConfig() == 0)
  413.         Exit(0);
  414. }
  415.  
  416. /*
  417. **  DebugOff -- Turn off debugging.
  418. **
  419. **    Parameters:
  420. **        None.
  421. **
  422. **    Returns:
  423. **        Nothing.
  424. **
  425. **    Side Effects:
  426. **        - Debug file is closed.
  427. */
  428. void
  429. DebugOff(signo)
  430.     int signo;
  431. {
  432.     if (DbgFp != NULL)
  433.         (void) fclose(DbgFp);
  434.  
  435.     DbgFp = NULL;
  436. }
  437.  
  438. /*
  439. **  DebugOn -- Turn on debugging.
  440. **
  441. **    Parameters:
  442. **        None.
  443. **
  444. **    Returns:
  445. **        Nothing.
  446. **
  447. **    Side Effects:
  448. **        - Debug file is opened/truncated if not already opened,
  449. **          otherwise do nothing.
  450. */
  451. void
  452. DebugOn(signo)
  453.     int signo;
  454. {
  455.     if (DbgFp == NULL) {
  456.         if ((DbgFp = fopen(DbgFile, "w")) == NULL)
  457.             syslog(LOG_ERR, "can't open debug file (%s)", DbgFile);
  458.     }
  459. }
  460.